﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

namespace MyLibrary.UI
{
    [DefaultProperty("Expression")]
    public class SelfValidateTextBox : TextBox
    {
        public enum KeepFocus
        {
            True,
            False
        }

        public enum ValidateType
        {
            /// <summary>
            /// 数字
            /// </summary>
            Number,
            /// <summary>
            /// 范围
            /// </summary>
            Range,
            /// <summary>
            /// 正则
            /// </summary>
            Regex

        }

        public enum ErrorHint
        {
            OnlyIcon,
            OnlyText,
            Both
        }
        
        private KeepFocus _keepFocus = KeepFocus.False;
        private bool _isValidated;  //控件是否验证通过
        private bool _isAllowEmpty = true; //控件内容是否为空
        private string _regexExpression = String.Empty; //控件匹配的正则表达式
        private string _errorMessage = String.Empty; //提示信息
        private bool _selectAllOnClick = true; //当点击控件时是否选择所有文字
        private bool _selectedAll = false; //获取控件的全选状态
        private ErrorProvider errorProvider = new ErrorProvider(); //提示控件
        private Label lable = new Label(); //提示标签
        private ErrorHint _errorHint = ErrorHint.OnlyIcon;  //错误提示只出现图标
        private ValidateType _vType = ValidateType.Regex;   //验证的方式
        private int _max = 100;
        private int _min = 0;

        private Container components = null;

        #region 属性
        public bool IsValidated
        {
            get { return _isValidated; }
        }
        [Category("验证"), Browsable(true), Description("验证用正则表达式")]
        public string RegexExpression
        {
            get { return _regexExpression; }
            set { _regexExpression = value; }
        }
        [Category("验证"), Editor(typeof(ValidateType), typeof(Enum)), Browsable(true), Description("控件的验证方式")]
        public ValidateType ValidatingType
        {
            get { return _vType; }
            set { _vType = value; }
        }
        [Category("验证"),Editor(typeof(KeepFocus),typeof(Enum)),Browsable(true),Description("设置当验证错误时,焦点是否留着错误的控件上")]
        public KeepFocus KeppFocusAfterValidate
        {
            get { return this._keepFocus; }
            set { this._keepFocus = value; }
        }
        [Category("验证"),Editor(typeof(ErrorHint),typeof(Enum)),Browsable(true),Description("验证错误时,提示的方式")]
        public ErrorHint ErrorHintMode
        {
            get { return this._errorHint; }
            set { this._errorHint = value; }
        }
        [Browsable(true), Category("验证"), DefaultValue(true), Description("设置控件的值是否允许为空")]
        public bool AllowEmpty
        {
            get { return _isAllowEmpty; }
            set { _isAllowEmpty = value; }
        }
        [Browsable(true), Category("验证"), Description("设置验证未通过时提示的内容")]
        public string ErrorMessage
        {
            get { return _errorMessage; }
            set { _errorMessage = value; }
        }
        [Browsable(false), Category("验证"), DefaultValue(true), Description("获取和设置此控件的全选状态")]
        public bool SelectAllOnClick
        {
            get { return _selectAllOnClick; }
            set { _selectAllOnClick = value; }
        }
        [Browsable(false), Category("验证"), DefaultValue(true), Description("获取和设置此控件的全选状态")]
        public bool SelectedAll
        {
            get { return _selectedAll; }
            set { _selectedAll = value; }
        }
        #endregion

        public SelfValidateTextBox()
        {
            InitializeComponent();
            
            //添加验证事件
            this.Validating += new CancelEventHandler(SelfValidateTextBox_Validating);
            this.Click += new EventHandler(SelfValidateTextBox_Click);
        }

        void SelfValidateTextBox_Click(object sender, EventArgs e)
        {
            if (this._selectAllOnClick && !this._selectedAll)
            {
                this.SelectAll();
                this._selectedAll = true;
            }
        }

        public void SelfValidateTextBox_Validating(object sender, CancelEventArgs e)
        {
            string expression = ((SelfValidateTextBox)sender).Text;
            ((SelfValidateTextBox)sender).SelectedAll = false;

            //如果输入值为空
            if (String.IsNullOrEmpty(expression.Trim()))
            {
                //如果设置允许空,则不做任何处理
                if (this._isAllowEmpty) return;
                this._isValidated = false;
            }
            //根据设置的验证方式进行验证
            else
            {
                switch (this.ValidatingType)
                {
                    case ValidateType.Number:
                        this._isValidated = this.ValidateNumber(expression);
                        break;
                    case ValidateType.Range:
                        this._isValidated = this.ValidateRange(expression);
                        break;
                    case ValidateType.Regex:
                        this._isValidated = this.ValidateRegex(expression);
                        break;
                }
            }

            if (this._isValidated)
            {
                errorProvider.Clear();
                this.Parent.Controls.Remove(lable);
            }
            else
            {
                switch (this._errorHint)
                {
                    case ErrorHint.OnlyIcon:
                        ErrorProviderMode((SelfValidateTextBox)sender);
                        break;
                    case ErrorHint.OnlyText:
                        ErrorTextMode((SelfValidateTextBox)sender, 2);
                        break;
                    case ErrorHint.Both:
                        ErrorProviderMode((SelfValidateTextBox)sender);
                        ErrorTextMode((SelfValidateTextBox)sender, 22);
                        break;
                }
                if (this._keepFocus == KeepFocus.True)
                    e.Cancel = true;
            }
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            this.ResumeLayout(false);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                    components.Dispose();
            }
            base.Dispose(disposing);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
        }

        #region 私有方法
        private bool ValidateNumber(string expression)
        {
            int result = 0;
            return Int32.TryParse(expression, out result);
        }

        private bool ValidateRange(string expression)
        {
            if (!ValidateNumber(expression))
                return false;

            int result = Convert.ToInt32(expression);
            if (result < this._min || result > this._max)
                return false;
            return true;
        }

        private bool ValidateRegex(string expression)
        {
            Regex regex = new Regex(this._regexExpression);
            return regex.IsMatch(expression);
        }

        private void ErrorProviderMode(SelfValidateTextBox box)
        {
            this.errorProvider.SetIconAlignment(box, ErrorIconAlignment.MiddleRight);
            this.errorProvider.SetIconPadding(box, 3);
            this.errorProvider.SetError(box, this._errorMessage);
        }
        private void ErrorTextMode(SelfValidateTextBox box, int offset)
        {
            Point p = new Point(box.Location.X + box.Size.Width + offset, box.Location.Y + 6);

            lable.AutoSize = true;
            lable.ForeColor = Color.Red;
            lable.Font = new Font("Arial", 12, FontStyle.Bold, GraphicsUnit.Pixel);
            lable.BackColor = Color.Transparent;
            lable.Location = p;
            lable.Text = this._errorMessage;
            box.Parent.Controls.Add(lable);
        }
        #endregion
    }
}
